
package hasthi.container;

import static hasthi.common.constants.WsrfConstants.WSA_ACTION_DELETE_RESOURCE_PROPERTY;
import static hasthi.common.constants.WsrfConstants.WSA_ACTION_GET_MULTIPLE_RESOURCE_PROPERTY_DOCUMENT;
import static hasthi.common.constants.WsrfConstants.WSA_ACTION_GET_RESOURCE_PROPERTY;
import static hasthi.common.constants.WsrfConstants.WSA_ACTION_GET_RESOURCE_PROPERTY_DOCUMENT;
import static hasthi.common.constants.WsrfConstants.WSA_ACTION_INSERT_RESOURCE_PROPERTY;
import static hasthi.common.constants.WsrfConstants.WSA_ACTION_QUERY_RESOURCE_PROPERTY;
import static hasthi.common.constants.WsrfConstants.WSA_ACTION_SET_RESOURCE_PROPERTY;
import static hasthi.common.constants.WsrfConstants.WSA_ACTION_UPDATE_RESOURCE_PROPERTY;
import hasthi.common.HasthiException;
import hasthi.common.HasthiException.FaultCode;
import hasthi.common.constants.HasthiConstants;
import hasthi.wsdm.ManagableResource;
import hasthi.wsdm.ManagedSystemHandle;
import hasthi.wsdm.ManagementAgentContext;
import hasthi.wsrf.ResourceManager;
import hasthi.wsrf.WSResource;
import hasthi.wsrf.WsrfException;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xmlbeans.XmlObject;
import org.w3.x2005.x08.addressing.EndpointReferenceType;

import wsdm.mows.EndpointReferenceDocument;
import wsrf.DeleteResourcePropertiesDocument;
import wsrf.GetMultipleResourcePropertiesDocument;
import wsrf.GetResourcePropertyDocument;
import wsrf.InsertResourcePropertiesDocument;
import wsrf.UpdateResourcePropertiesDocument;
import xsul.DataValidationException;
import xsul.soap.UnsupportedSoapVersion;
/**
 * Whoever wants to integrate XMF to his application should create a instance of XsulBasedWSDMProcessor from his XSUL container (with a 
 * sutable cnfiguration file) and for each incoming message call call isKnownMessage(..). If this return true, this is message for 
 * XMF and user should call processeMessage() and return response without further processing the message. 
 * @author Srinath Perera(hperera@cs.indiana.edu)
 */

public class XsulBasedWSDMProcessor {
    private Map<String,String> wsaActionMap = new HashMap<String, String>();
    private Map<String, String> soapActionMap = new HashMap<String, String>();
    private ResourceManager resourceManager;
    private final WSDMResourceLocater resourceLocater;
    private ManagementAgentContext context;
    
    private static Log log = LogFactory.getLog(HasthiConstants.AGENT_LOGGER_NAME);


    
    public XsulBasedWSDMProcessor(ManagementAgentContext context) throws HasthiException{
        this.context = context;
        resourceLocater = new WSDMResourceLocater(context);
        resourceManager = new ResourceManager(resourceLocater);
        resourceManager.setResourceListener(context.getChangeListener());
        
        //Add WSRF specific operation actions
        wsaActionMap.put(WSA_ACTION_GET_RESOURCE_PROPERTY_DOCUMENT, 
                "http://docs.oasis-open.org/wsrf/rpw-2/GetResourcePropertyDocument/GetResourcePropertyDocumentResponse");
        wsaActionMap.put(WSA_ACTION_GET_RESOURCE_PROPERTY, 
                "http://docs.oasis-open.org/wsrf/rpw-2/GetResourceProperty/GetResourcePropertyResponse");
        wsaActionMap.put(WSA_ACTION_GET_MULTIPLE_RESOURCE_PROPERTY_DOCUMENT, 
                "http://docs.oasis-open.org/wsrf/rpw-2/GetMultipleResourceProperties/GetMultipleResourcePropertiesResponse");
        wsaActionMap.put(WSA_ACTION_GET_MULTIPLE_RESOURCE_PROPERTY_DOCUMENT, 
                "http://docs.oasis-open.org/wsrf/rpw-2/QueryResourceProperties/QueryResourcePropertiesResponse");
        wsaActionMap.put(WSA_ACTION_QUERY_RESOURCE_PROPERTY, 
                "http://docs.oasis-open.org/wsrf/rpw-2/PutResourcePropertyDocument/PutResourcePropertyDocumentResponse");
        wsaActionMap.put(WSA_ACTION_SET_RESOURCE_PROPERTY, 
                "http://docs.oasis-open.org/wsrf/rpw-2/SetResourceProperties/SetResourcePropertiesResponse");
        wsaActionMap.put(WSA_ACTION_INSERT_RESOURCE_PROPERTY, 
                "http://docs.oasis-open.org/wsrf/rpw-2/InsertResourceProperties/InsertResourcePropertiesResponse");
        wsaActionMap.put(WSA_ACTION_UPDATE_RESOURCE_PROPERTY, 
                "http://docs.oasis-open.org/wsrf/rpw-2/UpdateResourceProperties/UpdateResourcePropertiesResponse");
        wsaActionMap.put(WSA_ACTION_DELETE_RESOURCE_PROPERTY, 
                "http://docs.oasis-open.org/wsrf/rpw-2/DeleteResourceProperties/DeleteResourcePropertiesResponse");
        soapActionMap.putAll(wsaActionMap);
    }
    
    
    public void addResource(ManagedSystemHandle systemHandle) throws HasthiException{
        ManagableResource resource = resourceLocater.addResource(systemHandle);
        //Add actions for operations defined in Manageable resource
        String[] actions = resource.getActionsForOperations();
        for(String action:actions){
            soapActionMap.put(action, action);
        }
        log.debug("resource "+ systemHandle.getResourceName() + "added to Management Agent");
    }
    
    
    public boolean isKnownMessage(MessageContext messageContext){
        String soapAction = messageContext.getSoapAction(); 
        if(soapAction != null){
            return soapActionMap.containsKey(soapAction);    
        }else{
            return false;
        }
    }
    
    public boolean isKnownMessage(String soapAction){
        if(soapAction != null){
            return soapActionMap.containsKey(soapAction);    
        }else{
            return false;
        }
    }
    
    public XmlObject processeMessage(MessageContext messageContext) throws HasthiException{
        try {
            XmlObject  requestAsXmlbeans = messageContext.getRequest();
            String wsaAction = messageContext.getSoapAction();
            XmlObject responseAsXmlbeans;

            //TODO find a better way to convert Epr to EndpointreferanceType so we do not love reference properties
            EndpointReferenceDocument eprDoc = EndpointReferenceDocument.Factory.newInstance();
            EndpointReferenceType epr = eprDoc.addNewEndpointReference();
            epr.addNewAddress().setStringValue(messageContext.getSoapEndpoint());
            if(isWsrfOperation(wsaAction)){
                if(WSA_ACTION_GET_RESOURCE_PROPERTY.equals(wsaAction)){
                    responseAsXmlbeans = resourceManager.getResourceProperty(epr, (GetResourcePropertyDocument)requestAsXmlbeans);
                }else if(WSA_ACTION_GET_RESOURCE_PROPERTY_DOCUMENT.equals(wsaAction)){
                    responseAsXmlbeans = resourceManager.getResourcePropertyDocument(epr);
                }else if(WSA_ACTION_GET_MULTIPLE_RESOURCE_PROPERTY_DOCUMENT.equals(wsaAction)){
                    responseAsXmlbeans = resourceManager.getMultipleResourceProperties(epr,(GetMultipleResourcePropertiesDocument)requestAsXmlbeans);
                }else if(WSA_ACTION_QUERY_RESOURCE_PROPERTY.equals(wsaAction)){
                    throw new UnsupportedOperationException();
                }else if(WSA_ACTION_SET_RESOURCE_PROPERTY.equals(wsaAction)){
                    throw new UnsupportedOperationException();
                }else if(WSA_ACTION_INSERT_RESOURCE_PROPERTY.equals(wsaAction)){
                    responseAsXmlbeans = resourceManager.insertResourceProperties(epr,(InsertResourcePropertiesDocument)requestAsXmlbeans);
                }else if(WSA_ACTION_UPDATE_RESOURCE_PROPERTY.equals(wsaAction)){
                    responseAsXmlbeans = resourceManager.updateResourceProperties(epr,(UpdateResourcePropertiesDocument)requestAsXmlbeans);
                }else if(WSA_ACTION_DELETE_RESOURCE_PROPERTY.equals(wsaAction)){                
                    responseAsXmlbeans = resourceManager.deleteResourceProperties(epr,(DeleteResourcePropertiesDocument)requestAsXmlbeans);
                }else{
                    throw new HasthiException("Unsupported operation "+wsaAction , FaultCode.UnsupportedMessage);
                }
            }else{
                WSResource resource = resourceLocater.findResource(epr);
                if(resource instanceof ManagableResource){
                    ManagableResource managableResource = (ManagableResource)resource;
                    responseAsXmlbeans =  managableResource.dispatchOperation(wsaAction, requestAsXmlbeans);
                }else{
                    throw new HasthiException("Non WSRF operations are allowd only for managable resource, "+epr.xmlText() + " is not  a managable resource", FaultCode.UnsupportedMessage);
                }
            }
            return responseAsXmlbeans;
//            XmlElement responseAsXml = XBeansUtil.xmlObjectToXmlElement(responseAsXmlbeans);
//            return soapFragrance.wrapBodyContent(responseAsXml);
        } catch (UnsupportedSoapVersion e) {
            throw new HasthiException(e,FaultCode.InvaliedRequest);
        } catch (DataValidationException e) {
            throw new HasthiException(e,FaultCode.InvaliedRequest);
        } catch (WsrfException e) {
            throw new HasthiException(e,FaultCode.InternalServiceError);            
        }
    }
    
    private boolean isWsrfOperation(String action){
        return wsaActionMap.containsKey(action);
    }
    
    public void shutdown() throws HasthiException{
        //TODO clean up resource manager and resoure locater
        resourceLocater.shutDownAllResources();
        this.context.shutDown();
        new Thread(new Runnable() {
            public void run() {
                try {
                    Thread.sleep(2*60*1000);
                    System.exit(0);
                } catch (InterruptedException e) {}
            }
        }).start();

    }
}

